GDB 生成 coredump:抓取运行中进程的内存快照
线上进程出了问题但没崩溃——内存缓慢增长、状态诡异地卡住、某个线程疑似死锁——这时候最想要的是一份「当时的完整现场」,又不能 kill 进程等它吐 core。GDB 的 generate-core-file 命令可以在 attach 到运行中进程后直接生成 coredump 文件,效果等同于进程崩溃时系统自动落盘的 core,之后完全可以离线慢慢分析。本文给出三种生成方式和一个容易踩的参数陷阱。
方法一:GDB 交互模式
bash
# attach 到目标进程
gdb -p <PID>
# 生成 coredump(可指定文件名)
(gdb) generate-core-file /tmp/core.myapp
# 不指定文件名则默认 core.<PID>
# 生成完毕后 detach 退出
(gdb) detach
(gdb) quit 适合需要先观察一下进程状态(线程栈、变量)再决定是否快照的场景。
方法二:一行命令(非交互)
bash
gdb -p <PID> -batch -ex "generate-core-file /tmp/core.myapp" -ex "detach" -batch 配合 -ex 不进交互界面,适合脚本化批量操作。
方法三:gcore
bash
# 直接在 shell 中生成,无需手动进入 GDB attach
gcore -o /tmp/core.myapp <PID>
# 注意:-o 指定的是文件名前缀,实际生成 /tmp/core.myapp.<PID> gcore 本质上是 GDB 的封装(内部同样会 ptrace attach 暂停目标进程),效果相同,使用最简洁。日常排查推荐它。
陷阱就在 -o 参数:它接受的是文件名前缀而不是完整文件名,gcore 会自动追加 .PID 后缀(依据 man gcore)。指望拿到 /tmp/core.myapp 的脚本,实际拿到的是 /tmp/core.myapp.12345,路径拼错就会以为生成失败。想精确控制完整文件名,用方法一或方法二。
注意事项
- 进程暂停:生成 coredump 期间进程会被暂停(STOP),进程越大耗时越长,生产环境慎用;
- 磁盘空间:coredump 文件大小约等于进程的 RSS,落盘前确认目标路径空间充足;
- 权限:需要对目标进程有 ptrace 权限(同用户或 root),受 Yama
ptrace_scope限制的环境需先放开; - 进程恢复:生成完成后进程自动恢复运行,不受影响;
- ulimit:
generate-core-file和gcore不受ulimit -c限制——它们由 GDB 直接写文件,不走内核的 core dump 管道。
离线分析
拿到 coredump 后与二进制一起打开:
bash
gdb /path/to/binary /tmp/core.myapp
# 常用分析命令
(gdb) bt # 查看调用栈
(gdb) info threads # 查看所有线程
(gdb) thread apply all bt # 所有线程调用栈 如果发布包里的二进制是 stripped 的,堆栈里只有地址没有函数名,需要配合调试符号包——可以参考《GDB attach 加载带调试信息的共享库符号》里的符号加载方法。
三种方式对比
| 方法 | 优点 | 缺点 |
|---|---|---|
| GDB 交互 | 可在生成前先检查进程状态 | 需要手动操作 |
| GDB -batch | 可脚本化,一行搞定 | 无法先检查 |
| gcore | 最简洁 | -o 是前缀不是文件名,功能单一 |
要点
- 未崩溃的进程也能拿「完整现场」:attach 后
generate-core-file或直接gcore gcore -o是前缀语义,产物会带.PID后缀,脚本里别拼错路径- 快照期间进程暂停,大进程在生产环境要评估停顿代价
- 产物不受
ulimit -c影响,但需要 ptrace 权限和约等于 RSS 的磁盘空间